package alingrad.engine.src.graphics;

/**
 * This class is used to contain data on an Animation.
 * It includes data on which frames of the Sprite array are included in the animation.
 * @author alingrad
 *
 */

public class Animation {

	/**
	 * Defaults animation goes from beginning to end
	 * Allows for custom animation patterns.
	 */
	public static final int TYPE_DEFAULT = 0;

	/**
	 * Back and Forth animation type goes from beginning to end back to beginning.
	 */
	public static final int TYPE_BACKFORTH = 1;

	/**
	 * Location in sprite array that this animation begins.
	 */
	private int frameStart;

	/**
	 * Location in sprite array that this animation ends.
	 */
	private int frameEnd;

	/**
	 * Delay (in milliseconds) between frames.
	 */
	private int frameDelay;

	/**
	 * Index of the current frame in the sprite array.
	 */
	public int frame;

	/**
	 * Amount of frame changes between updates.
	 */
	private int frameDelta;

	/**
	 * The animation type of the animation.
	 */
	private int animType = TYPE_DEFAULT;

	/**
	 * Whether or not the animation repeats.
	 */
	public boolean repeat = true;

	/**
	 * If the animation does not repeat, this value is set to true when the animation is complete.
	 */
	private boolean isDone = false;

	/**
	 * Direction the animation is moving.
	 */
	private int frameDirection;

	/**
	 * Amount of milliseconds that have passed in the current frame.
	 */
	private int currentFrameTime;

	/**
	 * Constructs a new Animation that contains no data.
	 */
	public Animation() {
	}

	/**
	 * Constructs a new Animation that contains the initial data.
	 * @param frameStart The index of the first frame of the animation in the sprite array.
	 * @param frameEnd The index of the last frame of the animation in the sprite array.
	 * @param frameDelay The delay (in milliseconds) between each frame.
	 */
	public Animation(int frameStart, int frameEnd, int frameDelay) {
		this.frameStart = frameStart;
		this.frameEnd = frameEnd;
		this.frameDelay = frameDelay;
	}

	/**
	 * Sets the Animation type.
	 * @param animType the animation type.
	 */
	public void setType(int animType) {
		this.animType = animType;
	}

	/**
	 * Resets the animation to its initial state.
	 */
	public void reset() {
		frame = frameStart;
		isDone = false;
		currentFrameTime = 0;
		if (animType == TYPE_BACKFORTH)
			frameDirection = 1;
	}

	/**
	 * Updates the animation to decide whether or not it needs to swap frames.
	 * @param delta time in milliseconds since the last update.
	 * @return the index of the current frame in the sprite array which needs to be drawn.
	 */
	public int update(long delta) {
		if (!isDone) {
			currentFrameTime += delta;
			if (currentFrameTime < frameDelay)
				return frame;
			if (animType == TYPE_DEFAULT)
				return updateFrame();
			else //if (animType == TYPE_BACKFORTH)
				return updateFrameBackForth();
		}else
			return frame;
	}

	/**
	 * Updates the animation to the correct frame if the type is equalt to {@link #TYPE_DEFAULT}.
	 * @return the index of the current frame in the sprite array which needs to be drawn.
	 */
	public int updateFrame() {
		frameDelta = 0;
		while (currentFrameTime > frameDelay) {
			currentFrameTime -= frameDelay;
			frameDelta++;
		}
		while (frameDelta > 0) {
			frameDelta--;
			frame++;
			if (repeat) {
				if (frame > frameEnd)
					frame = frameStart;
			}else {
				frame = frameEnd;
				isDone = true;
			}
		}
		return frame;
	}

	/**
	 * Updates the animation to the correct frame if the type is equal to {@link #TYPE_BACKFORTH}.
	 * @return the index of the current frame in the sprite array which needs to be drawn.
	 */

	private int updateFrameBackForth() {
		frameDelta = 0;
		while (currentFrameTime > frameDelay) {
			currentFrameTime -= frameDelay;
			frameDelta++;
		}
		while (frameDelta > 0) {
			frameDelta--;
			frame += frameDirection;
			if (frameDirection > 0) {
				if (frame > frameEnd) {
					frameDirection = -1;
					frame = frameEnd - 1;
				}
			}
			else {
				if (frame < frameStart) {
					if (repeat) {
						frameDirection = 1;
						frame = frameStart + 1;
					}else {
						frame = frameStart;
						isDone = true;
					}
				}
			}
		}
		return frame;
	}
}
